﻿using Abp.Application.Services;
using Abp.Runtime.Caching;
using Abp.UI;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using NetCore.Configuration;
using NetCore.Dtos;
using NetCore.Entities.Needs;
using NetCore.Extensions;
using NetCore.Interfaces;
using NetCore.Mail;
using NetCore.Needs.Dtos;
using NetCore.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace NetCore.Needs
{
    /// <summary>
    /// 需求
    /// </summary>
    [Description("需求")]
    public class NeedAppService : BaseNetCoreAppService<Need>, INeedAppService
    {
        private readonly IHostingEnvironment _env;
        private readonly IConfigurationRoot _appConfiguration;
        private readonly ICacheManager _cacheManager;
        private readonly IHttpContextAccessor _httpContext;
        private readonly INetCoreRepository<NeedAttachment> _needAttachmentRepository;
        public NeedAppService(IHostingEnvironment env,
            ICacheManager cacheManager,
            IHttpContextAccessor httpContext,
            INetCoreRepository<NeedAttachment> needAttachmentRepository,
            INetCoreRepository<Need> baseRepository) : base(baseRepository)
        {
            _env = env;
            _appConfiguration = AppConfigurations.Get(env.ContentRootPath, env.EnvironmentName, env.IsDevelopment());
            _httpContext = httpContext;
            _needAttachmentRepository = needAttachmentRepository;
            _cacheManager = cacheManager;
        }

        public async Task<IList<NeedDto>> Grid()
        {
            var virtualPath = $"{_env.WebRootPath}\\upload\\{nameof(Need)}";
            var result = BaseRepository.GetAll()
                .Select(m => new NeedDto
                {
                    Id = m.Id,
                    Name = m.Name,
                    //Sex = m.Sex,
                    Phone = m.Phone,
                    QNumber = m.QNumber,
                    Email = m.Email,
                    Requirements = m.Requirements,
                    CreationTime = m.CreationTime,
                    //AttachementsString = PopulateAttachements(m.Id, false),
                    Attachments = m.Attachments.Select(n => new NeedAttachmentDto
                    {
                        Id = n.Id,
                        NeedId = n.NeedId,
                        FilePath = n.FilePath,
                        VirtualPath = $"{virtualPath}\\{n.NeedId}\\{Path.GetFileName(n.FilePath)}"
                    }).ToList()
                }).OrderByDescending(o => o.CreationTime);

            return await result.ToListAsync();//BaseRepository.GetAll().ProjectTo<NeedDto>();
        }

        public string GetAttachmentName(NeedAttachment attachment)
        {
            try
            {
                string path = attachment.FilePath;
                string attachmentName = path.Substring(path.LastIndexOf("\\", StringComparison.Ordinal) + 1);
                return attachmentName;
                //var url = string.Format("/Need/Download/{0}", attachment.Id);
                //return string.Format("<a href='{0}'>{1}</a>", url, attachmentName);
            }
            catch
            {
                return string.Empty;
            }
        }

        public async Task Create(NeedCreateDto input)
        {
            // 验证码
            var checkCode = await _cacheManager.GetCache(NetCoreConsts.PersonalCaches).GetOrDefaultAsync("CheckCode");
            if (!input.Code.Equals(checkCode?.ToString(), StringComparison.CurrentCultureIgnoreCase))
            {
                throw new UserFriendlyException("验证码错误");
            }
            //自定义的上传文件最多21个...
            //model.AddFiles();
            var record = new Need
            {
                Name = input.Name,
                Sex = input.Sex,
                Email = input.Email,
                Phone = input.Phone,
                QNumber = input.QNumber,
                Requirements = input.Requirements
            };
            await BaseRepository.InsertAsync(record); //record update 到数据库
            //发送邮件
            var mailModel = new MailDto(_appConfiguration["Mail:SmtpHost"],
                _appConfiguration["Mail:UserName"], _appConfiguration["Mail:License"],
                _appConfiguration["Mail:MailFrom"], _appConfiguration["Mail:MailTo"],
                Convert.ToInt32(_appConfiguration["Mail:Port"]))
            {
                Cc = _appConfiguration["Mail:MailCC"],
                Subject = record.Name + _appConfiguration["Mail:Subject"],
                Body = GetMailBody(record)
            };

            //record.Attachments = model.Attachments;
            //上传的附件，循环赋值 model.UploadFiles或者 Request.Form.Files
            var targetPath = $"{ CustomConfigurationManager.WebRootPath}\\upload\\{record.Id}\\";//\\{model.UploadGuid}
            if (FileExtension.CreateFolderIfNeeded(targetPath))
            {
                var attatchments = new List<NeedAttachment>();
                //Request.Form.Files["files1"]
                var files = input.Files.Where(m => m != null).ToList();
                foreach (var file in files)
                {
                    var path = Path.Combine(targetPath, file.FileName);
                    FileExtension.SavaFile(file, path);
                    //添加attachments 并设置record 的attachments
                    attatchments.Add(new NeedAttachment
                    {
                        NeedId = record.Id,
                        FilePath = path
                    });
                    mailModel.AttachmentPaths.Add(path);
                }
                if (attatchments.Any())
                {
                    attatchments.ForEach(m => record.Attachments.Add(m));
                    //_needAttachmentService.Insert(attatchments);
                }
            }
            //send to mplh
            var mail = new MailService(mailModel);
            await mail.SendAsync();

            //send to customer
            mailModel.To = record.Email.Trim();
            mailModel.Body = GetMailBody(record, true);
            await mail.SendAsync(mailModel);
        }

        private string GetMailBody(Need record, bool sendToCustomer = false)
        {
            var title = _appConfiguration["Mail:Title"];
            var sign = _appConfiguration["Mail:Sign"];
            var note = "";
            var url = "";
            if (sendToCustomer)
            {
                title = _appConfiguration["Mail:CustomerTitle"] + record.Name + ",\n\n您提交的资料如下：";
                sign = _appConfiguration["Mail:CustomerSign"];
                note = "\n\n您的需求已收到，我们将尽快与您联系！";
                url = "\n\n" + _appConfiguration["Mail:WebsiteUrl"];
            }

            var body = title + "\n\n姓名：" + record.Name + "\n\n性别：" + record.Sex + "\n\n邮箱：" +
                       record.Email + "\n\n电话：" + record.Phone + "\n\nQQ：" + record.QNumber + "\n\n需求：" +
                       record.Requirements + note + "\n\n\n\n" + "With Best Regards,\n\n" + sign + url;
            var domail = _appConfiguration["App:ServerRootAddress"];

            body = $"<h1><img style='display:none;' src='{domail}/Need/IsReader?name={record.Phone ?? record.QNumber}' /></h1><img src='{domail}/images/ad.jpg' /><div>{body}</div>";

            return body;
        }
        /// <summary>
        /// 构造前端html下载标签
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task<string> PopulateAttachements(PopulateAttachementInputDto input)
        {
            var attatchments = await Get(m => m.Id == input.NeedId)
                .SelectMany(m => m.Attachments).ToListAsync();

            //var isShowDeleteTag = allowDelete;

            var attachmentsString = new StringBuilder();
            //var delList = new List<string>();
            attatchments.ForEach(att =>
            {
                //var downloadTag = "<a href='" + Url.Action("Download", "Need", new { id = att.Id }) + "'>" + GetAttachmentName(att) + "</a>";
                var downloadTag = $"<a href='/Need/Download?id={att.Id}'>" + GetAttachmentName(att) + "</a>";
                //if (isShowDeleteTag)
                //    downloadTag += "<span data-attatchment-id=\"" + att.Id + "\" class=" + "\"deltag\"" + ">x</span>";
                attachmentsString.Append(downloadTag + ", "); //delList.Add(downloadTag);
            });
            var delStr = attachmentsString.ToString().RemoveLastChar(',');//var delStr = string.Join(",", delList);
            return delStr;
            //return new HtmlString(str);
        }

        /// <summary>
        /// 提供给用户下载  返回文件流
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<IActionResult> Download(InputIdDto input)
        {
            var attachment = _needAttachmentRepository.Get(input.Id);
            if (attachment?.FilePath is null)
            {
                throw new UserFriendlyException("未找到附件!");
            }

            var filePath = attachment.FilePath;
            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(filePath, FileMode.Open))
            {
                await stream.CopyToAsync(memoryStream);
            }
            memoryStream.Seek(0, SeekOrigin.Begin);
            //文件名必须编码，否则会有特殊字符(如中文)无法在此下载。
            string encodeFilename = HttpUtility.UrlEncode(Path.GetFileName(filePath), Encoding.GetEncoding("UTF-8"));
            _httpContext.HttpContext.Response.Headers.Add("Content-Disposition", "attachment; filename=" + encodeFilename);
            return new FileStreamResult(memoryStream, "application/octet-stream");
        }


        /// <summary>
        /// 下载物理文件(给img标签 src属性)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<IActionResult> DownloadFile(InputIdDto input)
        {
            var attachment = await _needAttachmentRepository.GetAsync(input.Id);
            if (attachment is null) return null;
            var filePath = attachment.FilePath;
            //Microsoft.AspNetCore.Mvc.Core.dll
            return FileExtension.PhysicalFile(filePath, "image/jpg", Path.GetFileName(filePath));//PhysicalFile 直接返回物理文件,给href
            //直接返回文件
            //var physicalFileResult = new PhysicalFileResult(filePath, "image/jpg");
            //physicalFileResult.FileDownloadName = Path.GetFileName(filePath);
            //return physicalFileResult;
        }



        /// <summary>
        /// 提供给用户删除文件
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<IActionResult> Remove(InputIdDto input)
        {
            var attachment = await _needAttachmentRepository.GetAsync(input.Id);
            if (attachment is null) return null;
            if (File.Exists(attachment.FilePath))
            {
                File.Delete(attachment.FilePath);
            }
            await _needAttachmentRepository.DeleteAsync(input.Id);
            return SJson();
        }


        /// <summary>
        /// 根据主键删除实体
        /// </summary>
        /// <param name="input">主键Id</param>
        /// <returns></returns>
        [RemoteService(false), Description("删除数据")]//RemoteService(false) 禁止生成api
        public override IActionResult Delete(InputIdDto<int> input)
        {
            var need = BaseRepository.GetAll()
                .Include(n => n.Attachments)
                .FirstOrDefault(m => m.Id == input.Id);
            need?.Attachments.ToList().ForEach(attachment =>
            {
                if (File.Exists(attachment.FilePath))
                {
                    File.Delete(attachment.FilePath);
                }
            });
            return base.Delete(input);
        }

        /// <summary>
        /// 根据主键异步删除实体
        /// </summary>
        /// <param name="input">实体主键</param>
        /// <returns></returns>
        [Description("根据主键异步删除实体")]
        public override async Task<IActionResult> DeleteAsync(InputIdDto<int> input)
        {
            var need = await BaseRepository.GetAll()
                .Include(n => n.Attachments)
                .FirstOrDefaultAsync(m => m.Id == input.Id);
            need?.Attachments.ToList().ForEach(attachment =>
            {
                if (File.Exists(attachment.FilePath))
                {
                    File.Delete(attachment.FilePath);
                }
            });
            await _needAttachmentRepository.BulkDeleteAsync(need.Attachments.ToList());
            return await base.DeleteAsync(input);
        }

        /// <summary>
        /// 邮件是否已读
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<bool> IsReader(InputNameDto input)
        {
            //如果能进入，代表别人已经看了
            var record = await Get(m => m.Phone == input.Name || m.QNumber == input.Name).FirstOrDefaultAsync();
            if (record is null) return false;
            record.IsRead = true;
            record.ReadTime = DateTime.Now;
            return true;
        }
    }
}
